package binPack.shelfNextFit
{
	import binPack.Node;

	public class ShelfNextFitBinPack
	{
		private var  binWidth:int;
		private var  binHeight:int;
		
		private var  currentX:int;
		private var  currentY:int;
		private var  shelfHeight:int;
		
		private var usedSurfaceArea:uint;
		public function ShelfNextFitBinPack(width:int, height:int)
		{
			Init(width, height);
		}
		public function Init(width:int, height:int):void
		{
			binWidth = width;
			binHeight = height;
			
			currentX = 0;
			currentY = 0;
			shelfHeight = 0;
			usedSurfaceArea = 0;
		}
		
		public function Insert(width:int, height:int):Node
		{
			var newNode:Node = new Node();
			// There are three cases:
			// 1. short edge <= long edge <= shelf height. Then store the long edge vertically.
			// 2. short edge <= shelf height <= long edge. Then store the short edge vertically.
			// 3. shelf height <= short edge <= long edge. Then store the short edge vertically.
			
			// If the long edge of the new rectangle fits vertically onto the current shelf,
			// flip it. If the short edge is larger than the current shelf height, store
			// the short edge vertically.
			if (((width > height && width < shelfHeight) ||	(width < height && height > shelfHeight)))
			{
				newNode.flipped = true;
				//swap(width, height);
				var t:int = width;
				width = height;
				height = t;
			}else{
				newNode.flipped = false;
			}
				
			
			if (currentX + width > binWidth){
				currentX = 0;
				currentY += shelfHeight;
				shelfHeight = 0;
				
				// When starting a new shelf, store the new long edge of the new rectangle horizontally
				// to minimize the new shelf height.
				if (width < height){
					//swap(width, height);
					t = width;
					width = height;
					height = t;
					newNode.flipped = !newNode.flipped;
				}
			}
			
			// If the rectangle doesn't fit in this orientation, try flipping.
			if (width > binWidth || currentY + height > binHeight){
				//swap(width, height);
				var t:int = width;
				width = height;
				height = t;
				newNode.flipped = !newNode.flipped;
			}
			
			// If flipping didn't help, return failure.
			if (width > binWidth || currentY + height > binHeight){
//				memset(&newNode, 0, sizeof(Node));
				return newNode;
			}
			
			newNode.width = width;
			newNode.height = height;
			newNode.x = currentX;
			newNode.y = currentY;
			
			currentX += width;
			shelfHeight = Math.max(shelfHeight, height);
			
			usedSurfaceArea += width * height;
			
			return newNode;
		}
		
		/// Computes the ratio of used surface area.
		public function Occupancy():Number
		{
			return usedSurfaceArea / (binWidth * binHeight);
		}
	}
}